package com.atom.plugin.core.utils

import java.io.*
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.zip.ZipFile

object IOUtils {
    /**
     * Judge if `input` is a real zip or jar file.
     * For handling special case in Wechat plugin that generates a path list by writing paths
     * into a file whose name ends with `PathUtil.DOT_JAR`
     *
     * @param input
     * File to judge with.
     *
     * @return
     * true - if input is a real zip or jar file.
     * false - if input is not a real zip or jar file.
     */
    @JvmStatic
    fun isRealZipOrJar(input: File): Boolean {
        var zf: ZipFile? = null
        return try {
            zf = ZipFile(input)
            true
        } catch (e: Exception) {
            false
        } finally {
            closeQuietly(zf)
        }
    }

    /**
     * Copy `srcFile` to `destFile`.
     *
     * @param src
     * Source file.
     * @param dest
     * Destination file.
     *
     * @throws IOException
     */
    @JvmStatic
    @kotlin.jvm.Throws(IOException::class)
    fun copyFile(src: File, dest: File) {
        if (!dest.exists()) {
            dest.parentFile.mkdirs()
        }
        Files.copy(
            src.toPath(), dest.toPath(),
            StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING
        )
    }

    /**
     * Copy data in `is` to `os` **without** closing any of these streams.
     *
     * @param is
     * Data source.
     * @param os
     * Data destination.
     * @param buffer
     * Buffer used to temporarily hold copying data, if `null` is passed, a new buffer
     * will be created in each invocation of this method.
     *
     * @throws IOException
     */
    @JvmStatic
    @kotlin.jvm.Throws(IOException::class)
    fun copyStream(`is`: InputStream, os: OutputStream, bufferArgs: ByteArray?) {
        var buffer = bufferArgs
        if (buffer == null || buffer.isEmpty()) {
            buffer = ByteArray(4096)
        }
        var bytesCopied: Int
        while (`is`.read(buffer).also { bytesCopied = it } >= 0) {
            os.write(buffer, 0, bytesCopied)
        }
        os.flush()
    }

    /**
     * Copy data in `is` to `os` **without** closing any of these streams.
     *
     * @param is
     * Data source.
     * @param os
     * Data destination.
     *
     * @throws IOException
     */
    @JvmStatic
    @kotlin.jvm.Throws(IOException::class)
    fun copyStream(`is`: InputStream, os: OutputStream) {
        copyStream(`is`, os, null)
    }

    /**
     * Close `target` quietly.
     *
     * @param obj
     * Object to be closed.
     */
    @JvmStatic
    fun closeQuietly(obj: Any?) {
        if (obj == null) {
            return
        }
        when (obj) {
            is Closeable -> {
                try {
                    obj.close()
                } catch (ignored: Throwable) {
                    // ignore
                }
            }
            is AutoCloseable -> {
                try {
                    obj.close()
                } catch (ignored: Throwable) {
                    // ignore
                }
            }
            is ZipFile -> {
                try {
                    obj.close()
                } catch (ignored: Throwable) {
                    // ignore
                }
            }
            else -> {
                throw IllegalArgumentException("obj $obj is not closeable")
            }
        }
    }
}